﻿using System;
using System.Collections.Async;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Net.Http;
using System.Runtime.InteropServices.WindowsRuntime;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Windows.Security.Cryptography;
using Windows.Security.Cryptography.Core;
using Windows.Storage.Streams;

namespace SuperTTS
{
    public class TTS
    {
        /// <summary>
        /// 语音播报人
        /// </summary>
        public enum VID_ENUM
        {
            小英 = 65040,
            小薛 = 65320,
            百合仙子 = 62060,
            伟香主 = 62070,
            四川方言 = 68060,
            东北话 = 68040,
            陕西方言 = 68080,
            _0 = 65080,
            _1 = 65010,
            _2 = 65070,
            _3 = 64010,
            _4 = 60020,
            _5 = 60030,
            _6 = 65180,
            _8 = 60161,
            _9 = 60130,
            _10 = 68030,
            _11 = 68010,
            _14 = 65360,
            _15 = 65090,
            _16 = 69055,
            _17 = 65340,
            _18 = 69010,
            _19 = 69020,
            _21 = 67020, _22 = 67010, _23 = 65110, _24 = 67030, _25 = 60100, _26 = 62020, _27 = 62010, _29 = 68120, _30 = 69030, _31 = 67230, _32 = 67100, _33 = 60170, _34 = 60120, _37 = 60150, _38 = 65310, _39 = 65250, _40 = 65270, _41 = 64410, _42 = 64430, _43 = 64450, _44 = 64180, _45 = 64470, _46 = 62240,
        }
        public async static Task<byte[]> GetPlayBytes(string[] say_list, int vid, int volume = 0, int speed = 0, Action<(int allcount, int make_num, int make_bytes)> callfun = null)
        {
            List<SayVO> newList = new List<SayVO>();
            foreach (var p in say_list)
            {
                newList.Add(new SayVO()
                {
                    msg = p,
                    bytes = new byte[] { }
                });
            }
            byte[] allbyte = new byte[] { };

            Debug.WriteLine("共:" + newList.Count + "个");
            int make_num = 0;
            await newList.Select(x => x).ParallelForEachAsync(async (v) =>
            {
                var playurl = await GetPlayUrl(v.msg, vid, volume, speed);
                StringContent sc = new StringContent("");
                //存储二进制
                var item = await Tools.GetHtml.GetPostHtmlAsync<StringContent>(new Action<HttpClient>((r) =>
                {
                    r.DefaultRequestHeaders.Add("Host", "proxy.peiyinge.com:17063");
                    r.DefaultRequestHeaders.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36");
                }), new Uri(playurl), sc, "get");
                v.bytes = await item.ReadAsByteArrayAsync();
                System.Threading.Interlocked.Increment(ref make_num);
                Debug.WriteLine("已处理:" + make_num + " 收到:" + v.bytes.Length + "个字节");
                callfun?.Invoke((newList.Count, make_num, v.bytes.Length));
            }, 10);

            foreach (var say_msg in newList)
            {
                allbyte = Tools.MakeBytes.AddBytes(allbyte, say_msg.bytes);
            }
            return allbyte;
        }
        /// <summary>
        /// 讲语音转换成数据流
        /// </summary>
        /// <param name="say_list">说话列表</param>
        /// <param name="vid"></param>
        /// <param name="volume"></param>
        /// <param name="speed"></param>
        /// <returns></returns>
        public async static Task<byte[]> GetPlayBytes(string[] say_list, VID_ENUM vid = VID_ENUM.伟香主, int volume = 0, int speed = 0,Action<(int allcount, int make_num, int make_bytes)> callfun=null)
        {
            return await GetPlayBytes(say_list,(int)vid,volume,speed,callfun);
        }

        public async static Task<string> GetPlayUrl(string say_msg, int vid = (int)VID_ENUM.伟香主, int volume = 0, int speed = 0)
        {
            //解析
            var DATAAUDIT = "IWl8I1gpXFNxJnhQSEQyS0drJVMuPmdEN24iSllTJlhOOGZ8Xiw0RjBCRUZlPzw/cWpBWHY1bzpoPjxOeCNQKg==";
            string synth_text_hash_code = Tools.MakeEncryption.Md5(say_msg, "x2", Encoding.UTF8).ToLower();
            var INPUT_JSON = "{\"channel\": \"10000001\",\"synth_text_hash_code\":\"" + synth_text_hash_code + "\"}";
            byte[] outputb = System.Convert.FromBase64String(DATAAUDIT);
            string c = Encoding.UTF8.GetString(outputb);

            string myAES = string.Empty;
            var b = c.Substring(16, c.Length - 16 - 16);
            for (int i = 0; i < b.Length; i += 2)
            {
                myAES += b.Substring(i, 1);
            }


            string req = string.Empty;

            req = Encrypt(INPUT_JSON, myAES);

            string post = Tools.MakeJson.ObjectToJson(new
            {
                req
            });
            var cookie = new System.Net.CookieContainer();
            //cookie.SetCookies(new Uri("http://www.peiyinge.com"), "JSESSIONID=D909323A74591FA2962C5C5587FB67D0; Hm_lvt_e1c12991ac3cea4a9a64c5da306d6f4d=1535080674; wf_tid=37869985584d; wf_rid=3cd9a830960a; gdt_fp=7a157237d71e65cb31bb751417e7c55e; xl_showData_7=shown; xl_showData_8=shown; Hm_lpvt_e1c12991ac3cea4a9a64c5da306d6f4d=1535093518;");

            //var html = await Tools.GetHtml.GetHtmlFromUrlAsync(new Action<System.Net.HttpWebRequest>((r) =>
            //{
            //    r.Accept = "*/*";

            //    r.Method = "POST";
            //    r.Headers["ContentLength"] = post.Length.ToString();

            //    r.ContentType = "application/json";
            //    r.Headers["Host"] = "www.peiyinge.com";
            //    r.Headers["Origin"] = "http://www.peiyinge.com";
            //    r.Headers["Referer"] = "http://www.peiyinge.com/make/";
            //    r.Headers["UserAgent"] = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36";
            //}), "http://www.peiyinge.com/web-server/1.0/works_synth_sign",
            //post, cookie, null);


            /*
             *       
             *          
             *    r.Accept = "*
                r.Method = "POST";
            r.KeepAlive = true;
            r.ContentLength = post.Length;
            r.ContentType = "application/json";
            r.Host = "www.peiyinge.com";
            r.Headers.Add("Origin", "http://www.peiyinge.com");
            r.Referer = "http://www.peiyinge.com/make/";

            r.UserAgent = "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36";

            *
            */

            StringContent sc = new StringContent(post);

            sc.Headers.ContentType = new System.Net.Http.Headers.MediaTypeHeaderValue("application/json");
            sc.Headers.ContentLength = post.Length;

            var html = await Tools.GetHtml.GetPostHtmlAsync<StringContent>((r) =>
            {
                r.BaseAddress = new Uri("http://www.peiyinge.com");
                r.DefaultRequestHeaders.Add("Accept", "*/*");
                r.DefaultRequestHeaders.Add("Method", "POST");
                r.DefaultRequestHeaders.Add("KeepAlive", "true");
                r.DefaultRequestHeaders.Add("ContentLength", post.Length.ToString());
                r.DefaultRequestHeaders.Host = "www.peiyinge.com";
                r.DefaultRequestHeaders.Add("Origin", "http://www.peiyinge.com");
                r.DefaultRequestHeaders.Referrer = new Uri("http://www.peiyinge.com/make/");
                r.DefaultRequestHeaders.Add("UserAgent", "Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/68.0.3440.7 Safari/537.36");
            }, new Uri("http://www.peiyinge.com/web-server/1.0/works_synth_sign"), sc);


            string _html = await html.ReadAsStringAsync();
            //解析json
            var jobj = Tools.MakeJson.JsonToLinqObject(_html);
            int status = jobj.GetValue("status").ToObject<int>();
            if (status == 0)
            {
                string body = jobj.GetValue("body").ToObject<string>();
                //body解析Base64
                var bodybytes = System.Convert.FromBase64String(body);
                string dec_str = Decrypt(bodybytes, myAES);
                //解析dec_str
                var _decobj = Tools.MakeJson.JsonToLinqObject(dec_str);
                string sign_text = _decobj.GetValue("sign_text").ToObject<string>();
                int time_stamp = _decobj.GetValue("time_stamp").ToObject<int>();

                string synthServer = "http://proxy.peiyinge.com:17063/synth";
                //播放地址
                string play_url = $"{synthServer}?ts={time_stamp}&sign={sign_text}&vid={(int)vid}&volume={volume}&speed={speed}&content={System.Net.WebUtility.UrlEncode(say_msg).ToLower()}";
                return play_url;
            }
            return string.Empty;
        }

        /// <summary>
        /// 获取播放地址
        /// </summary>
        /// <param name="say_msg">播放内容</param>
        /// <param name="vid">播音员ID</param>
        /// <param name="volume"></param>
        /// <param name="speed">语速200为1.4倍</param>
        /// <returns></returns>
        public async static Task<string> GetPlayUrl(string say_msg, VID_ENUM vid = VID_ENUM.伟香主, int volume = 0, int speed = 0)
        {
            return await GetPlayUrl(say_msg, (int)vid, volume, speed);
        }


        /// <summary>

        /// AES解密

        /// </summary>

        /// <param name="decryptStr">密文</param>

        /// <param name="key">密钥</param>

        /// <returns></returns>

        private static string Decrypt(byte[] decryptBytes, string _key)
        {

            var keyArray = CryptographicBuffer.ConvertStringToBinary(_key, BinaryStringEncoding.Utf8);

            var toEncryptArray = decryptBytes.AsBuffer();

            var provider = SymmetricKeyAlgorithmProvider
                   .OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
            
            var myKey = provider.CreateSymmetricKey(keyArray);
            //进行加密
            var msg = CryptographicEngine.Decrypt(myKey, toEncryptArray, null);
            
            return UTF8Encoding.UTF8.GetString(msg.ToArray());
        }


        /// <summary>

        /// AES加密

        /// </summary>

        /// <param name="encryptStr">明文</param>

        /// <param name="key">密钥</param>

        /// <returns></returns>

        private static string Encrypt(string encryptStr, string _key)
        {
            byte[] keyArray = UTF8Encoding.UTF8.GetBytes(_key);

            byte[] toEncryptArray = UTF8Encoding.UTF8.GetBytes(encryptStr);

            var provider = SymmetricKeyAlgorithmProvider
                   .OpenAlgorithm(SymmetricAlgorithmNames.AesEcbPkcs7);
            var myKey = provider.CreateSymmetricKey(keyArray.AsBuffer());
            //进行加密
            var msg = CryptographicEngine.Encrypt(myKey, toEncryptArray.AsBuffer(),null);

            return System.Convert.ToBase64String(msg.ToArray(), 0, msg.ToArray().Length);

        }
    }
}
